package com.q3d.demo.svc.gateway.config.local;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.springdoc.core.AbstractSwaggerUiConfigProperties;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.SwaggerUiConfigParameters;
import org.springdoc.core.SwaggerUiConfigProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.SpecVersion;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;

@Configuration /** 作用于 Bean 类的属性配置 */
/**
 * 配置 SpringDoc
 * 开启 Swagger，访问地址：http://{host}:{port}/{context-path}/swagger-ui/index.html
 * 并同时提供 JSON 数据接口：http://{host}:{port}/{context-path}/v3/api-docs/
 * 
 * @author 叶湘 ( weixin:yexiang841, email:yexiang841@qq.com )
 */
public class SpringDocConfig {

    @Value(value = "${spring.application.name}") /** 读取配置文件（或远程配置）数据 */
    public String applicationName;

    @Value(value = "${spring.profiles.active}") /** 读取配置文件（或远程配置）数据 */
    public String profilesActive;

    protected final SwaggerUiConfigProperties swaggerUiConfigProperties;
    protected final RouteDefinitionLocator routeDefinitionLocator;

    public SpringDocConfig(SwaggerUiConfigProperties swaggerUiConfigProperties,
            RouteDefinitionLocator routeDefinitionLocator) {
        this.swaggerUiConfigProperties = swaggerUiConfigProperties;
        this.routeDefinitionLocator = routeDefinitionLocator;
    }

    @Bean
    public OpenAPI openApi() {
        return new OpenAPI().specVersion(SpecVersion.V31).info(new Info().title("Q3D Service API Docs")
                .description("Module：" + applicationName)
                .version("v1.0.0")
                .contact(new Contact()
                        .name("叶湘")
                        .url("weixin:yexiang841")
                        .email("yexiang841@qq.com")));
    }

    @Bean
    @Lazy(false)
    public List<GroupedOpenApi> apis(SwaggerUiConfigParameters swaggerUiConfigParameters,
            RouteDefinitionLocator locator) {
        List<GroupedOpenApi> groupedOpenApiList = new ArrayList<>();
        List<RouteDefinition> routeDefinitionList = locator.getRouteDefinitions().collectList().block();
        routeDefinitionList.stream()
                // 以 ReactiveCompositeDiscoveryClient_ 开头的是注册中心提供的服务名
                .filter(routeDefinition -> routeDefinition.getId().matches("ReactiveCompositeDiscoveryClient_.*"))
                .forEach(routeDefinition -> {
                    // 获取原本的服务名
                    String serviceName = routeDefinition.getId().replace("ReactiveCompositeDiscoveryClient_", "")
                            .toLowerCase();
                    // 以服务名作为 api 分组名（在 Swagger-UI 显示为下拉列表）
                    swaggerUiConfigParameters.addGroup(serviceName);
                    // 做 Uri 到分组的映射
                    GroupedOpenApi.builder()
                            .group(serviceName)
                            .pathsToMatch("/" + serviceName + "/**")
                            .build();
                });
        return groupedOpenApiList;
    }

    @PostConstruct
    public void autoInitSwaggerUrls() {
        List<RouteDefinition> routeDefinitionList = routeDefinitionLocator.getRouteDefinitions().collectList().block();
        routeDefinitionList.stream()
                // 以 ReactiveCompositeDiscoveryClient_ 开头的是注册中心提供的服务名
                .filter(routeDefinition -> routeDefinition.getId().matches("ReactiveCompositeDiscoveryClient_.*"))
                .forEach(routeDefinition -> {
                    // 获取原本的服务名
                    String serviceName = routeDefinition.getId().replace("ReactiveCompositeDiscoveryClient_", "")
                            .toLowerCase();
                    String uri = routeDefinition.getUri().toString();
                    AbstractSwaggerUiConfigProperties.SwaggerUrl swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl(
                            serviceName,
                            uri.replace("lb://", "").toLowerCase() + "/v3/api-docs",
                            serviceName);
                    Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> urls = swaggerUiConfigProperties.getUrls();
                    if (urls == null) {
                        urls = new LinkedHashSet<>();
                        swaggerUiConfigProperties.setUrls(urls);
                    }
                    urls.add(swaggerUrl);
                });
    }

}